package com.bdy.lm.taximanager.port;

import android.util.Log;

import com.bdy.lm.taximanager.app.MyApp;
import com.bdy.lm.taximanager.http.HttpJson;
import com.bdy.lm.taximanager.model.Fare;
import com.bdy.lm.taximanager.model.MessagePackaging;
import com.bdy.lm.taximanager.model.RunningTaximeterState;
import com.bdy.lm.taximanager.model.SerialPortData;
import com.bdy.lm.taximanager.util.JsonUtils;
import com.bdy.lm.taximanager.util.TimeUtils;

import org.apache.log4j.Logger;
import org.json.JSONObject;

import java.io.IOException;
import java.math.BigInteger;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import android_serialport_api.SerialPort;
import de.greenrobot.event.EventBus;

/**
 * Created by liming on 2017/5/31 0031.
 */

public class TaxiMeterDataAnalysis implements TSerialPort.TSerialPortDelegate{

    private String license;//车牌号
    private String tradePermission;//经营许可证号
    private String employId;//驾驶员从业资格证号
    private String up;//上车时间
    private String down;//下车时间
    private double sum;//金额
    private double price;//单价
    private double distance;//总里程
    private String spentTime;//用时
    private double fuelSurcharge;//燃油附加费
    private String waitTime;//等待计时
    private String transitionType;//交易类型
    private int currentRunTime;//当前车次
    private int hour;
    private int minute;
    private double nRun;//空驶里程
    private String journey;//运行状态（单程或往返）

    public static Fare queryParameter;
    public static String taximeterTime = "";
    public static final String LOCAL = "local", SERVER = "server";
    private boolean finishParameterQuery = false;
    private LocalQueryParameter localQueryParameter;

    private boolean finishMeterPointQuery = false;
    public static final String VERIFY_ADJUST = "verifyAdjust", TAXI_INFO = "taxiInfo";
    private LocalQueryLicense localQueryLicense;

    private HttpJson httpJson = new HttpJson();

    private String queryTime;
    private double meterPoint;

    private PassTransitionInfo passTransitionInfo;
    private PassQueryMeterData passQueryMeterData;

    //private SerialPortData serialPortData = new SerialPortData();
    private SerialPortData.TransitionData transitionData = SerialPortData.getInstance().getTransitionData();
    private SerialPortData.QueryMeterPointData queryMeterPointData = SerialPortData.getInstance().getQueryMeterPointData();
    private SerialPortData.GetupData getupData = SerialPortData.getInstance().getGetupData();
    public static TaxiMeterDataAnalysis taxiMeterDataAnalysis;

    private TSerialPort mTSerialPort;

    private Executor executor;

    //交易开始头                                 //起始位          //包长度      设备类型    厂商标识1  命令字2
    private final byte[] transitionBeginHead = {0x55, (byte)0xaa, 0x00, 0x0b, 0x02,   (byte)0xf1,  0x00, (byte)0xe7};
    //交易结束头
    private final byte[] transitionResultHead = {0x55, (byte)0xaa, 0x00, 0x48, 0x02, (byte)0xf1, 0x00, (byte)0xe8};

    //查询里程点指令
    private final byte[] queryMeterCommand = {0x55, (byte)0xaa, 0x00, 0x04, 0x02, (byte)0xf1, (byte)0xf1, 0x01, (byte)0xee, 0x55, (byte)0xaa};
    //查询里程点，计价器返回数据头
    private final byte[] queryMeterHead = {0x55, (byte)0xaa, 0x00, 0x14, 0x02, (byte)0xf1, (byte)0xf1, 0x01};

    //查询时间和K值
    private final byte[] queryTimeK = {0x55, (byte)0xaa, 0x00, 0x04, 0x02, (byte)0xf1, (byte)0xf1, (byte)0x0e, (byte)0xee, 0x55, (byte)0xaa};
    //查询时间和K值应答数据头
    private final byte[] queryTimeKResponseHead = {0x55, (byte)0xaa, 0x00, 0x0c, 0x02, (byte)0xf1, (byte)0xf1, (byte)0x0e};

    //修改时间和K值
    private byte[] modifyTimeK = new byte[19];
    //修改时间和K值，计价器的应答数据
    private final byte[] modifyTimeKResponse = {0x55, (byte)0xaa, 0x00, 0x04, 0x02, (byte)0xf1, (byte)0xf1, 0x0f, (byte)0xee, 0x55, (byte)0xaa};

    //运价查询指令
    private final byte[] queryFare = {0x55, (byte)0xaa, 0x00, 0x04, 0x02, (byte)0xf1, (byte)0x00, (byte)0x04, (byte)0xee, 0x55, (byte)0xaa};
    //运价查询，计价器返回数据头
    private final byte[] queryFareResponseHead = {0x55, (byte)0xaa, 0x00, 0x44, 0x02, (byte)0xf1, (byte)0x00, (byte)0x04};

    //修改运价指令
    private byte[] modifyFare = new byte[75];
    //修改计价器运价返回
    private final byte[] modifyFareResponse = {0x55, (byte)0xaa, 0x00, (byte)0x04, 0x02, (byte)0xf1, 0x00, 0x05, (byte)0xee, 0x55, (byte)0xaa};

    //重车过程发送显示信息
    private final byte[] runningStateHead = {0x55, (byte)0xaa, 0x00, (byte)0x11, 0x02, (byte)0xf1, (byte)0xf1, (byte)0xe8};

    private Logger logger;

    public static TaxiMeterDataAnalysis newInstance() {
        if(taxiMeterDataAnalysis == null) {
            taxiMeterDataAnalysis = new TaxiMeterDataAnalysis();
            return taxiMeterDataAnalysis;
        } else {
            return taxiMeterDataAnalysis;
        }
    }

    private TaxiMeterDataAnalysis() {
        logger = Logger.getLogger(this.getClass());
        executor = Executors.newSingleThreadExecutor();
        // 打开串口，接收计价器的数据
        mTSerialPort = new TSerialPort(this);
        try {
            mTSerialPort.open(MyApp.serialName1, MyApp.serialBaudRate);//ttyS0
        } catch (Exception e) {
            Log.d("TaxiMeterDataAnalysis", "串口ttyS0打开错误");
            logger.error("串口ttyS0打开错误\n" + e);
            EventBus.getDefault().post("串口ttyS0打开错误");
            try {
                mTSerialPort.open(MyApp.serialName0, MyApp.serialBaudRate);//ttyTCC2
                logger.info("串口ttyTCC2打开成功");
            } catch (Exception e1) {
                EventBus.getDefault().post("串口ttyTCC2打开错误");
                logger.error("串口ttyTCC2打开错误\n" + e1);
                Log.d("TaxiMeterDataAnalysis", "串口ttyTCC2打开错误");
                try {
                    mTSerialPort.open(MyApp.serialName2, MyApp.serialBaudRate);//打开配置文件中的串口号
                } catch (IOException e2) {
                    EventBus.getDefault().post("配置文件中串口配置错误");
                    logger.error("配置文件中串口配置错误\n" + e1);
                    Log.d("TaxiMeterDataAnalysis", "配置文件中串口配置错误");
                }
            }
        }
    }

    public void setPassTransitionInfoCallBack(PassTransitionInfo passTransitionInfo) {
        this.passTransitionInfo = passTransitionInfo;
    }
    public void setPassQueryMeterDataCallBack(PassQueryMeterData passQueryMeterData) {
        this.passQueryMeterData = passQueryMeterData;
    }

    @Override
    public void processSerialPortData(List data) {
        int length = data.size();
        byte[] d = new byte[data.size()];
        System.out.print("SerialPort转化数据：");
        for(int i = 0; i < length; i++) {
            d[i] = (byte)data.get(i);
            System.out.print(Integer.toHexString(d[i] & 0xff) + " ");
        }
        //System.out.println("Demo NewTaxi length = " + length);
        if(compare(transitionResultHead, d, 8)) {//解析交易结果
            transitionAnalysis(d);
            Log.d("SerialPort", transitionData.toString());
            Log.d("SerialPort", SerialPortData.getInstance().toString());
            //传递交易数据到MainActivity
            if (passTransitionInfo != null) {
                passTransitionInfo.passTransitionInfo(transitionData);
            }
        } else if(compare(queryMeterHead, d, 8)) {//解析查询里程数据
            queryMeterAnalysis(d);
            Log.d("SerialPort", queryMeterPointData.toString());
            finishMeterPointQuery = true;
        } else if(compare(transitionBeginHead, d, 8)) {//解析上车数据
            getUpAnalysis(d);
            Log.d("SerialPort", getupData.toString());
            logger.info("SerialPort解析上车数据" + getupData.toString());
            if (passTransitionInfo != null) {
                passTransitionInfo.passGetupInfo(getupData);
            }
        } else if(compare(modifyFareResponse, d, 8)) {//修改计价器运价响应
            //数据区长6字节,1字节结果，0x00成功，0x01失败，0x02相同无需设置，0xff设备不支持
            //修改成功后返回一个长6字节时间，YYYYMMDDhh
            logger.info("修改计价器运价成功");//getFareStartTime(d)
        } else if(compare(queryFareResponseHead, d, 8)) {//查询计价器运价响应头
            queryParameter = getQueryFare(d);
            System.out.println("查询计价器运价" + queryParameter);
            logger.info("查询计价器运价" + queryParameter);
            queryTimeAndK();
        } else if(compare(queryTimeKResponseHead, d, 8)) {//查询时间和K值响应头
            queryParameter.setK(getK(d));
            taximeterTime = getTime(d);
            System.out.println("查询时间和K值" + taximeterTime);
            finishParameterQuery = true;
        } else if(compare(modifyTimeKResponse, d, 8)) {//修改时间和K值响应，不带结果码
            logger.info("修改计价器时间和K值成功");//修改成功
        } else if(compare(runningStateHead, d, 8)) {//重车过程发送显示信息,固定周期发送
            System.out.println("重车过程" + d);
            passTransitionInfo.passRunningState(getRunningTaximeterState(d));
        }
    }
    public void getMeterPoint(final String identity){
        queryMeter();
        executor.execute(new Runnable() {
            @Override
            public void run() {
                while (!finishMeterPointQuery) {
                    delay(100);
                }
                if (identity.equals(VERIFY_ADJUST) && passQueryMeterData != null) {
                    passQueryMeterData.passQueryMeterData(queryMeterPointData);
                } else if (identity.equals(TAXI_INFO) && localQueryLicense != null) {
                    localQueryLicense.passLicense(queryMeterPointData.getLicense());
                }
                finishMeterPointQuery = false;
            }
        });
    }
    public void getTaximeterParameter(final String identity) {
        queryTaximeterParameter();
        executor.execute(new Runnable() {
            @Override
            public void run() {
                while (!finishParameterQuery) {
                    delay(100);
                }
                if (identity.equals(LOCAL)) {
                    localQueryParameter.passParameter();
                    System.out.println("TaxiMeterDataAnalysis local getTaximeterParameter");
                } else if (identity.equals(SERVER)) {
                    uploadParameter();
                    System.out.println("TaxiMeterDataAnalysis server getTaximeterParameter");
                }
                finishParameterQuery = false;
            }
        });
    }

    /**
     * 上传查询到的计价器参数
     */
    private void uploadParameter() {
        System.out.println("查询计价器全部参数" + queryParameter);
        logger.info("查询计价器全部参数" + queryParameter);
        Map<String, Object> msg = new MessagePackaging(115).getFareInfoMap();
        msg.put("parameter", JsonUtils.gson.toJson(queryParameter));
        msg.put("taximeterTime", taximeterTime);
        msg.put("queryTime", TimeUtils.getFormatTime());
        final JSONObject js = JsonUtils.mapToJsonObject(msg);
        executor.execute(new Runnable() {
            @Override
            public void run() {
                while (httpJson.getPostJson() == null) {
                    httpJson.HttpJsonPost(js, MyApp.serverUrl);
                    System.out.println("上传查询的计价器全部参数" + js.toString());
                    delay(3000);
                }
                httpJson.setPostJson(null);
            }
        });
    }

    /**
     * 解析交易结果
     * @param d
     */
    private void transitionAnalysis(byte[] d) {
        this.license = new String(d, 8, 6);//ASCII字符，无溢出
        SerialPortData.getInstance().getTransitionData().setLicense(license);
        this.tradePermission = turnToString(d, 14, 16);
        SerialPortData.getInstance().getTransitionData().setTradePermission(tradePermission);
        this.employId = turnToString(d, 30, 19);
        SerialPortData.getInstance().getTransitionData().setEmployId(employId);
        this.up = turnUpTime(d);
        transitionData.setUp(up);
        this.down = turnDownTime(d);
        transitionData.setDown(down);
        //getSpendTime(d[52], d[53], d[54], d[55]);
        //transitionData.setHour(hour);
        //transitionData.setMinute(minute);
        transitionData.setSpentTime(TimeUtils.getTimeDiff(up + ":00", down + ":00"));
        this.distance = ((d[56] & 0xf0) >> 4) * 10000 + (d[56] & 0x0f) * 1000 +
                        ((d[57] & 0xf0) >> 4) * 100 + (d[57] & 0x0f) * 10 +
                        ((d[58] & 0xf0) >> 4) + (d[58] & 0x0f) * 0.1;
        transitionData.setDistance(distance);
        this.nRun = ((d[59] & 0xf0) >> 4) * 100 + (d[59] & 0x0f) * 10 + ((d[60] & 0xf0) >> 4)  + (d[60] & 0x0f) * 0.1;
        transitionData.setnRun(nRun);
        this.fuelSurcharge = ((d[61] & 0xf0) >> 4) * 10000 + (d[61] & 0x0f) * 1000 +
                             ((d[62] & 0xf0) >> 4) * 100 + (d[62] & 0x0f) * 10 +
                             ((d[63] & 0xf0) >> 4) + (d[63] & 0x0f) * 0.1;
        transitionData.setFuelSurcharge(fuelSurcharge);
        this.waitTime = String.valueOf(((d[64] & 0xf0) >> 4) * 10 + (d[64] & 0x0f)) + ":" + String.valueOf(((d[65] & 0xf0) >> 4) * 10 + d[65] & 0x0f);
        transitionData.setWaitTime(waitTime);
        this.sum = ((d[66] & 0xf0) >> 4) * 10000 + (d[66] & 0x0f) * 1000 +
                   ((d[67] & 0xf0) >> 4) * 100 + (d[67] & 0x0f) * 10 +
                   ((d[68] & 0xf0) >> 4) + (d[68] & 0x0f) * 0.1;
        transitionData.setSum(sum);
        this.price = 2.0;
        transitionData.setPrice(price);
        this.currentRunTime = (d[69] << 24) + (d[70] << 16) + (d[71] << 8) + d[72];
        transitionData.setCurrentRunTime(currentRunTime);
        this.transitionType = turnToTransitionType(d[73]);
        transitionData.setTransitionType(transitionType);
        //transitionData.setRunState(SerialPortData.noneRun);
        SerialPortData.getInstance().setTransitionData(transitionData);
    }

    /**
     * 解析查询里程数据
     * @param d
     */
    private void queryMeterAnalysis(byte[] d) {
        this.license = new String(d, 8, 6);
        queryMeterPointData.setLicense(license);
        this.queryTime = "20" + Integer.toHexString(d[14]) + "-" +Integer.toHexString(d[15]) + "-" + Integer.toHexString(d[16]) + " " +//年月日
                         Integer.toHexString(d[17]) + ":" + Integer.toHexString(d[18]) + ":" + Integer.toHexString(d[19]);//时分秒
        queryMeterPointData.setQueryTime(queryTime);
        this.meterPoint = ((d[20] & 0xf0) >> 4) * 10000 + (d[20] & 0x0f) * 1000 +
                          ((d[21] & 0xf0) >> 4) * 100 + (d[21] & 0x0f) * 10 +
                          ((d[22] & 0xf0) >> 4) + (d[22] & 0x0f) * 0.1 +
                          ((d[23] & 0xf0) >> 4) * 0.01 + (d[23] & 0x0f) * 0.001;
        queryMeterPointData.setMeterPoint(meterPoint);
        SerialPortData.getInstance().setQueryMeterPointData(queryMeterPointData);
    }

    /**
     * 对比两个数组的前n个字节是否完全一样
     * @param a 第一个数组
     * @param b 第二个数组
     * @param n 第二个数组的前n个字节
     * @return 比较内容是否相同，相同为true
     */
    private boolean compare(byte[] a, byte[] b, int n) {
        for(int i = 0; i < n; i++) {
            if(a[i] != b[i]) {
                return false;
            }
        }
        return true;
    }

    /**
     * 将byte恢复成原来整形数据
     * @param b
     * @param bb b的开始下标
     * @param length b中要转化的长度
     * @return 转化的字符串结果
     */
    private String turnToString(byte[] b, int bb, int length) {
        StringBuilder r = new StringBuilder();
        for(int i = 0; i < length; i++) {
            r.append(b[i + bb] & 0xff);
        }
        return r.toString();
    }

    /**
     * 解析上车数据
     * @param d
     */
    private void getUpAnalysis(byte[] d) {
        StringBuilder r = new StringBuilder();
        r.append("20");
        r.append(((d[9] & 0xf0) >> 4) * 10 + (d[9] & 0x0f));//年
        r.append("-");
        r.append(((d[10] & 0xf0) >> 4) * 10 + (d[10] & 0x0f));//月
        r.append("-");
        r.append(((d[11] & 0xf0) >> 4) * 10 + (d[11] & 0x0f));//日
        r.append(" ");
        r.append(((d[12] & 0xf0) >> 4) * 10 + (d[12] & 0x0f));//时
        r.append(":");
        r.append(((d[13] & 0xf0) >> 4) * 10 + (d[13] & 0x0f));//分
        this.up = r.toString();
        getupData.setUp(up);
        getupData.setRunState(SerialPortData.run);
        SerialPortData.getInstance().setGetupData(getupData);
    }

    /**
     * 将上车时间转化
     * @param d
     * @return
     */
    private String turnUpTime(byte[] d) {
        StringBuilder r = new StringBuilder();
        r.append("20");
        r.append(((d[49] & 0xf0) >> 4) * 10 + (d[49] & 0x0f));//年
        r.append("-");
        r.append(((d[50] & 0xf0) >> 4) * 10 + (d[50] & 0x0f));//月
        r.append("-");
        r.append(((d[51] & 0xf0) >> 4) * 10 + (d[51] & 0x0f));//日
        r.append(" ");
        r.append(((d[52] & 0xf0) >> 4) * 10 + (d[52] & 0x0f));//时
        r.append(":");
        r.append(((d[53] & 0xf0) >> 4) * 10 + (d[53] & 0x0f));//分
        return r.toString();
    }

    /**
     * 转化下车时间
     * @param d
     * @return
     */
    private String turnDownTime(byte[] d) {
        StringBuilder r = new StringBuilder();
        r.append("20");
        r.append(((d[49] & 0xf0) >> 4) * 10 + (d[49] & 0x0f));//年
        r.append("-");
        r.append(((d[50] & 0xf0) >> 4) * 10 + (d[50] & 0x0f));//月
        r.append("-");
        int hj = ((d[52] & 0xf0) >> 4) * 10 + (d[52] & 0x0f);
        int hc = ((d[54] & 0xf0) >> 4) * 10 + (d[54] & 0x0f);
        if(hc < hj) {
            r.append(((d[51] & 0xf0) >> 4) * 10 + (d[51] & 0x0f) + 1);//日
        } else {
            r.append(((d[51] & 0xf0) >> 4) * 10 + (d[51] & 0x0f));
        }
        r.append(" ");
        r.append(hc);//时
        r.append(":");
        r.append(((d[55] & 0xf0) >> 4) * 10 + (d[55] & 0x0f));//分
        return r.toString();
    }

    /**
     * 转化交易类型
     * @param d
     * @return
     */
    private String turnToTransitionType(byte d) {
        if(d == 0x00) {
            return "cash";
        } else if(d == 0x01) {
            return "M1";
        } else if(d == 0x03) {
            return "cpu";
        } else {
            return "other";
        }
    }

    /**
     * 获取所用时间
     * @param hj 起始小时
     * @param mj 起始分钟
     * @param hc 结束小时
     * @param mc 结束分钟
     */
    private void getSpendTime(byte hj, byte mj, byte hc, byte mc) {
        int bh, bm;//前一天过去的时间和分钟
        if(hc < hj) {
            bh = 23 - hj;
            bm = 60 - mj;
            if(bm + mc > 60) {
                this.hour = bh + hc + 1;
                this.minute = bm + mc -60;
            } else {
                this.hour = bh + hc;
                this.minute = bm + mc;
            }
        } else {
            if(mc < mj) {
                this.hour = hc - hj -1;
                this.minute = mc + 60 -mj;
            } else {
                this.hour = hc - hj;
                this.minute = mc - mj;
            }
        }
    }

    /**
     *  将一个两位的十进制数转化为BCD码
     * @param d 两位的十进制数
     * @return BCD码的byte类型
     */
    private byte parseBCD(int d) {
        return (byte) (((d / 10) << 4) + (d % 10));
    }

    /**
     * 构造修改运价命令
     * @param fare 运价
     * @throws ParseException 数据转换异常
     */
    private void getModifyFare(Fare fare) throws ParseException {
        //开始 8
        byte[] head = {0x55, (byte)0xaa, 0x00, (byte)0x44, 0x02, (byte)0xf1, 0x00, 0x05};
        //结束 3
        byte[] end = {(byte)0xee, 0x55, (byte)0xaa};
        //系统预留 22
        byte[] ruf = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
        //厂商自定义1
        byte[] selfDefine = {0x0};
        System.arraycopy(head, 0, modifyFare, 0, 8);
        Calendar c = TimeUtils.getCalender(fare.getFareFrom());
        //参数启用时间
        modifyFare[8] = parseBCD(c.get(Calendar.YEAR) / 100);
        modifyFare[9] = parseBCD(c.get(Calendar.YEAR) - 2000);
        modifyFare[10] = parseBCD(c.get(Calendar.MONTH) + 1);
        modifyFare[11] = parseBCD(c.get(Calendar.DAY_OF_MONTH));
        modifyFare[12] = 0;//时，暂不同
        //白天往返单价
        int pd = (int) (Double.parseDouble(fare.getPriceDay()) * 100);
        modifyFare[13] = parseBCD(pd / 100);
        modifyFare[14] = parseBCD(pd % 100);
        //夜间往返单价
        int pn = (int) (Double.parseDouble(fare.getPriceNight()) * 100);
        modifyFare[15] = parseBCD(pn / 100);
        modifyFare[16] = parseBCD(pn % 100);
        //白天单程单价
        modifyFare[17] = parseBCD(pd / 100);
        modifyFare[18] = parseBCD(pd % 100);
        //夜间单程单价
        modifyFare[19] = parseBCD(pn / 100);
        modifyFare[20] = parseBCD(pn % 100);
        //白天二次空贴单价
        modifyFare[21] = 0;
        modifyFare[22] = 0;
        //夜间二次空贴单价
        modifyFare[23] = 0;
        modifyFare[24] = 0;
        //白天起步价
        int fdd = (int) (Double.parseDouble(fare.getFareDayDown()) * 100);
        modifyFare[25] = parseBCD(fdd / 100);
        modifyFare[26] = parseBCD(fdd % 100);
        //夜间起步价
        int fnd = (int) (Double.parseDouble(fare.getFareNightDown()) * 100);
        modifyFare[27] = parseBCD(fnd / 100);
        modifyFare[28] = parseBCD(fnd % 100);
        //续程里程数
        modifyFare[29] = 0;
        modifyFare[30] = 0;
        //启程公里 XX.XX
        int dd = (int) (Double.parseDouble(fare.getDownDistance()) * 100);
        modifyFare[31] = parseBCD(dd / 100);
        modifyFare[32] = parseBCD(dd % 100);
        //单程公里
        modifyFare[33] = 0;
        modifyFare[34] = 0;
        //二次空贴公里
        modifyFare[35] = 0;
        modifyFare[36] = 0;
        //白天等候时间单价 XX.XX
        int fw = (int) (Double.parseDouble(fare.getFareWait()) * 100);
        modifyFare[37] = parseBCD(fw / 100);
        modifyFare[38] = parseBCD(fw % 100);
        //夜间等候时间单价 XX.XX
        modifyFare[39] = parseBCD(fw / 100);
        modifyFare[40] = parseBCD(fw % 100);
        //免费等候时间MMss
        modifyFare[41] = 0;
        modifyFare[42] = 0;
        //加价时间MMss
        modifyFare[43] = 0;
        modifyFare[44] = 0;
        //夜间开始时间
        modifyFare[45] = parseBCD(TimeUtils.getTimeParse(fare.getNigthFrom()).getHours());
        modifyFare[46] = parseBCD(TimeUtils.getTimeParse(fare.getNigthFrom()).getMinutes());
        //夜间结束时间
        modifyFare[47] = parseBCD(TimeUtils.getTimeParse(fare.getNightEnd()).getHours());
        modifyFare[48] = parseBCD(TimeUtils.getTimeParse(fare.getNightEnd()).getMinutes());
        System.arraycopy(ruf, 0, modifyFare, 49, 22);
        System.arraycopy(selfDefine, 0, modifyFare, 71, 1);
        System.arraycopy(end, 0, modifyFare, 72, 3);
    }

    /**
     * 将计价器返回的数据转化
     * @param d 计价器数据
     * @return
     */
    private Fare getQueryFare(byte[] d){
        Fare fare = new Fare();
        //参数启用时间
        int year = ((d[8] & 0xf0) >> 4) * 1000 + (d[8] & 0xf) * 100 + ((d[9] & 0xf0) >> 4) * 10 + (d[9] & 0xf);
        int month = ((d[10] & 0xf0) >> 4) * 10 + (d[10] & 0xf);
        int day = ((d[11] & 0xf0) >> 4) * 10 + (d[11] & 0xf);
        int hour = ((d[12] & 0xf0) >> 4) * 10 + (d[12] & 0xf);
        fare.setFareFrom("" + year + "-" + month + "-" + day);
        //白天往返单价
        double a1 = turnToDouble(d[13], d[14]);
        fare.setPriceDay(Double.toString(a1));
        //夜间往返单价
        double a2 = turnToDouble(d[15], d[16]);
        fare.setPriceNight(Double.toString(a2));
        //白天单程单价
        double a3 = turnToDouble(d[17], d[18]);
        //夜间单程单价
        double a4 = turnToDouble(d[19], d[20]);
        //白天二次空贴单价
        double a5 = turnToDouble(d[21], d[22]);
        //夜间二次空贴单价
        double a6 = turnToDouble(d[23], d[24]);
        //白天起步价
        double a7 = turnToDouble(d[25], d[26]);
        fare.setFareDayDown(Double.toString(a7));
        //夜间起步价
        double a8 = turnToDouble(d[27], d[28]);
        fare.setFareNightDown(Double.toString(a8));
        //续程里程数
        double a9 = turnToDouble(d[29], d[30]);
        //启程公里 XX.XX
        double a10 = turnToDouble(d[31], d[32]);
        //单程公里
        double a11 = turnToDouble(d[33], d[34]);
        //二次空贴公里
        double a12 = turnToDouble(d[35], d[36]);
        //白天等候时间单价 XX.XX
        double a13 = turnToDouble(d[37], d[38]);
        fare.setFareWait(Double.toString(a13));
        //夜间等候时间单价 XX.XX
        double a14 = turnToDouble(d[39], d[40]);
        //免费等候时间MMss
        int mm1 = ((d[41] & 0xf0) >> 4) * 10 + (d[41] & 0xf);
        int ss1 = ((d[42] & 0xf0) >> 4) * 10 + (d[42] & 0xf);
        //加价时间MMss
        int mm2 = ((d[43] & 0xf0) >> 4) * 10 + (d[43] & 0xf);
        int ss2 = ((d[44] & 0xf0) >> 4) * 10 + (d[44] & 0xf);
        //夜间开始时间
        int h1 = ((d[45] & 0xf0) >> 4) * 10 + (d[45] & 0xf);
        int m1 = ((d[46] & 0xf0) >> 4) * 10 + (d[46] & 0xf);
        fare.setNigthFrom("" + h1 + ":" + m1 + ":00");
        //夜间结束时间
        int h2 = ((d[47] & 0xf0) >> 4) * 10 + (d[47] & 0xf);
        int m2 = ((d[48] & 0xf0) >> 4) * 10 + (d[48] & 0xf);
        fare.setNightEnd("" + h2 + ":" + m2 + ":00");
        return fare;
    }

    /**
     * 将两位BCD码转化为double类型，格式为XX.XX
     * @param h 高位
     * @param l 低位
     * @return
     */
    private double turnToDouble(byte h, byte l){
        return ((h & 0xf0) >> 4) * 10 + (h & 0xf) + ((l & 0xf0) >> 4) * 0.1 + (l & 0xf) * 0.01;
    }

    /**
     * 从计价器数据获取时间 YYYY-MM-DD HH:MM:SS
     * @param d
     * @return
     */
    private String getTime(byte[] d){
        int year = ((d[8] & 0xf0) >> 4) * 10 + (d[8] & 0xf);
        int month = ((d[9] & 0xf0) >> 4) * 10 + (d[9] & 0xf);
        int day = ((d[10] & 0xf0) >> 4) * 10 + (d[10] & 0xf);
        int hour = ((d[11] & 0xf0) >> 4) * 10 + (d[11] & 0xf);
        int minute = ((d[12] & 0xf0) >> 4) * 10 + (d[12] & 0xf);
        int second = ((d[13] & 0xf0) >> 4) * 10 + (d[13] & 0xf);
        return "20" + year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
    }

    /**
     * 从计价器数据获取K值
     * @param d
     * @return
     */
    private String getK(byte[] d){
        return new BigInteger(1, new byte[]{d[14], d[15]}).toString(10);
    }

    /**
     * 解析运价设置后的返回信息 启用时间，格式YYYYMMDDhh
     * @param d
     * @return
     */
    private String getFareStartTime(byte[] d){
        //参数启用时间
        int year = ((d[9] & 0xf0) >> 4) * 1000 + (d[9] & 0xf) * 100 + ((d[10] & 0xf0) >> 4) * 10 + (d[10] & 0xf);
        int month = ((d[11] & 0xf0) >> 4) * 10 + (d[11] & 0xf);
        int day = ((d[12] & 0xf0) >> 4) * 10 + (d[12] & 0xf);
        int hour = ((d[13] & 0xf0) >> 4) * 10 + (d[13] & 0xf);
        return "" + year + month + day + hour;
    }
    /**
     * 查询里程点
     * @return
     */
    private boolean queryMeter() {
        return mTSerialPort.sendData(queryMeterCommand);
    }

    /**
     * 查询计价器参数
     * @return
     */
    private boolean queryTaximeterParameter() {
        return queryFare();
    }

    /**
     * 查询时间和K值
     * @return
     */
    private boolean queryTimeAndK() {
        return mTSerialPort.sendData(queryTimeK);
    }

    /**
     *  修改时间和K值
     * @param k K值
     * @return
     */
    public boolean modifyTimeAndK(int k) {
        System.arraycopy(modifyTimeKResponse, 0, modifyTimeK, 0, 8);
        modifyTimeK[3] = 0x0c;//长度为12
        int[] time = TimeUtils.getCurrentTime();
        for (int i = 0; i < 6; i++) {
            modifyTimeK[i + 8] = parseBCD(time[i]);
        }
        modifyTimeK[14] = (byte) (k / 256);
        modifyTimeK[15] = (byte) (k % 256);
        modifyTimeK[16] = (byte) 0xee;
        modifyTimeK[17] = (byte) 0x55;
        modifyTimeK[18] = (byte) 0xaa;
        System.out.println("修改时间和K值" + Arrays.toString(modifyTimeK));
        return mTSerialPort.sendData(modifyTimeK);
    }

    /**
     * 查询运价
     */
    private boolean queryFare() {
        System.out.println("查询运价" + Arrays.toString(queryFare));
        return mTSerialPort.sendData(queryFare);
    }
    /**
     * 修改运价，同时修改K值
     * @param fare 运价
     * @return
     */
    public boolean modifyFare(Fare fare) {
        modifyTimeAndK(Integer.parseInt(fare.getK()));
        try {
            getModifyFare(fare);
        } catch (ParseException e) {
            e.printStackTrace();
            return false;
        }
        System.out.print("MySerialData:");
        for (int i = 0; i < modifyFare.length; i++) {
            System.out.print(Integer.toHexString(modifyFare[i] & 0xff) + " ");
        }
        //return true;
        return mTSerialPort.sendData(modifyFare);
    }

    /**
     * 将串口数据转化为计价器状态信息
     * @param d
     * @return
     */
    private RunningTaximeterState getRunningTaximeterState(byte[] d) {
        RunningTaximeterState state = new RunningTaximeterState();
        String[] s = {"", "", "", "", "", "", "", ""};
        String[] allState = {"低速", "保留", "保留", "暂停", "IC卡", "单程", "往返", "夜间"};
        byte[] r = getBooleanArray(d[8]);
        for (int i = 0; i < 8; i++) {
            if ((r[i] == 1) && (i != 1) && (i != 2)) {
                s[i] = allState[i];
            }
        }
        state.setTaximeterState(s);
        double p = ((d[9] & 0xf0) >> 4) * 10000 + (d[9] & 0xf) * 1000 + ((d[10] & 0xf0) >> 4) * 100 + (d[10] & 0xf) * 10 + ((d[11] & 0xf0) >> 4) + (d[11] & 0xf) * 0.1;
        state.setPrice(p);
        double m = ((d[12] & 0xf0) >> 4) * 10000 + (d[12] & 0xf) * 1000 + ((d[13] & 0xf0) >> 4) * 100 + (d[13] & 0xf) * 10 + ((d[14] & 0xf0) >> 4) + (d[14] & 0xf) * 0.1;
        state.setMeters(m);
        int[] wait = new int[3];
        wait[0] = ((d[15] & 0xf0) >> 4) * 10 + (d[15] & 0xf);
        wait[1] = ((d[16] & 0xf0) >> 4) * 10 + (d[16] & 0xf);
        wait[2] = ((d[17] & 0xf0) >> 4) * 10 + (d[17] & 0xf);
        state.setWaiting(wait);
        double money = ((d[18] & 0xf0) >> 4) * 10000 + (d[18] & 0xf) * 1000 + ((d[19] & 0xf0) >> 4) * 100 + (d[19] & 0xf) * 10 + ((d[20] & 0xf0) >> 4) + (d[20] & 0xf) * 0.1;
        state.setMoney(money);
        return state;
    }

    /**
     * 获取byte数据每一bit位上的值
     * @param b
     * @return
     */
    public byte[] getBooleanArray(byte b) {
        byte[] array = new byte[8];
        for (int i = 0; i < 8; i++) {
            array[i] = (byte)(b & 1);
            b = (byte) (b >> 1);
            System.out.println(i + ": " + array[i]);
        }
        return array;
    }

    /**
     * 延时 单位：毫秒
     * @param time
     */
    private void delay(int time) {
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
            logger.error(e);
            e.printStackTrace();
        }
    }
    public interface PassTransitionInfo {
        void passTransitionInfo(SerialPortData.TransitionData transitionData);
        void passGetupInfo(SerialPortData.GetupData getupData);
        void passRunningState(RunningTaximeterState state);
    }
    public interface PassQueryMeterData {
        void passQueryMeterData(SerialPortData.QueryMeterPointData queryMeterPointData);
    }

    public void setLocalQueryParameter(LocalQueryParameter localQueryParameter) {
        this.localQueryParameter = localQueryParameter;
    }

    public interface LocalQueryParameter {
        void passParameter();
    }
    public void setLocalQueryLicense(LocalQueryLicense localQueryLicense){
        this.localQueryLicense = localQueryLicense;
    }
    public interface LocalQueryLicense {
        void passLicense(String license);
    }
}
